﻿// <com.woyouqiu.Copyright>
// --------------------------------------------------------------
// <copyright>上海有求网络科技有限公司 2015</copyright>
// <Solution>MyCompany.MyProject</Solution>
// <Project>MyCompany.MyProject.Core</Project>
// <FileName>IpHelpService.cs</FileName>
// <CreateTime>2017-04-22 16:56</CreateTime>
// <Author>何苗</Author>
// <Email>hemiao@woyouqiu.com</Email>
// <log date="2017-04-22 16:56" version="00001">创建</log>
// --------------------------------------------------------------
// </com.woyouqiu.Copyright>

using System;
using System.ComponentModel.DataAnnotations;
using System.Net.Http;
using System.Reflection;
using System.Threading.Tasks;
using Abp.Application.Services;
using Abp.Configuration;
using Abp.Extensions;
using Abp.Runtime.Validation;
using Abp.UI;
using Newtonsoft.Json;
using Vecen.BangChuang.BangChuang.Areas.Dtos;

namespace Vecen.BangChuang.BangChuang.Areas {
    /// <summary>
    /// 
    /// </summary>
    [RemoteService(false)]
    public class AddressHelper: BangChuangAppServiceBase {
        /// <summary>
        /// 根据IP获得地址信息
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public Task<string> GetAreaCodeByIp(string ip) {
            return GetFromTaoBao(ip);
        }

        private async Task<string> GetFromTaoBao(string ip) {
            if(ip.IsNullOrWhiteSpace()) {
                throw new UserFriendlyException("请求失败!", "Ip地址为空!");
            }
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri("http://ip.taobao.com/");


            Logger.InfoFormat("请求淘宝IP库开始:{0}", ip);
            var responseMessage = await client.GetAsync(string.Format("/service/getIpInfo.php?ip={0}", ip));
            var result = await responseMessage.Content.ReadAsStringAsync();
            Logger.InfoFormat("请求淘宝IP库结束:{0},返回结果:{1}", ip, result);

            if(result.StartsWith("{\"code\":0")) {
                var taobaoIp = JsonConvert.DeserializeObject<TaoBaoIpSuccess>(result);

                //区/县
                if(!taobaoIp.Data.County_Id.IsNullOrWhiteSpace() && taobaoIp.Data.County_Id != "-1") {
                    return taobaoIp.Data.County_Id.Substring(0, 6);
                }
                //市
                if(!taobaoIp.Data.City_Id.IsNullOrWhiteSpace() && taobaoIp.Data.City_Id != "-1") {
                    return taobaoIp.Data.City_Id.Substring(0, 4);
                }
                //省
                if(!taobaoIp.Data.Region_Id.IsNullOrWhiteSpace() && taobaoIp.Data.Region_Id != "-1") {
                    return taobaoIp.Data.Region_Id.Substring(0, 2);
                }

                throw new UserFriendlyException("请求失败!", "未获取到IP定位城市!");
            } else {
                var errorInfo = JsonConvert.DeserializeObject<TaoBaoIpError>(result);
                if(errorInfo.Data == "invaild ip.") {
                    throw new UserFriendlyException("请求失败!", "无效的IP地址!");
                } else {
                    throw new UserFriendlyException("请求失败!", errorInfo.Data);
                }
            }
        }

        private async Task<string> GetFromAmap(string ip) {
            string amapKey = SettingManager.GetSettingValueForApplication(BangChuangConsts.SettingsName.ThirdApi.ThirdApi_Amap_WebApi_Key);
            if(ip.IsNullOrWhiteSpace()) {
                throw new UserFriendlyException("请求失败!", "Ip地址为空!");
            }
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri("http://restapi.amap.com/");
            Logger.InfoFormat("请求高德IP库开始:{0}", ip);
            var responseMessage =
                await client.GetAsync(string.Format("/v3/ip?ip={0}&output=json&key={1}", ip, amapKey));
            var result = await responseMessage.Content.ReadAsStringAsync();
            Logger.InfoFormat("请求高德IP库结束:{0},返回结果:{1}", ip, result);

            if(result.StartsWith("{\"status\"")) {
                var amapIp = JsonConvert.DeserializeObject<AmapIp>(result);
                if(amapIp.Status == 1) {
                    return amapIp.Adcode;
                }
            }
            return null;
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="coordinate"></param>
        /// <returns></returns>
        public async Task<string> GetAreaCodeByCoordinate(Coordinate coordinate) {
            string amapKey = SettingManager.GetSettingValueForApplication(BangChuangConsts.SettingsName.ThirdApi.ThirdApi_Amap_WebApi_Key);
            if(coordinate == null) {
                throw new UserFriendlyException("请求失败!", "coordinate为空!");
            }
            HttpClient client = new HttpClient();
            client.BaseAddress = new Uri("http://restapi.amap.com/");
            Logger.InfoFormat("请求高德逆地理编码开始:{0}", coordinate);

            AmapGeocodeParam param = new AmapGeocodeParam(amapKey, coordinate);

            var responseMessage = await client.GetAsync(string.Format("/v3/geocode/regeo?{0}", param));
            var result = await responseMessage.Content.ReadAsStringAsync();
            Logger.InfoFormat("请求高德逆地理编码结束:{0},返回结果:{1}", param, result);

            if(result.StartsWith("{\"status\"")) {
                var amapIp = JsonConvert.DeserializeObject<Rootobject>(result);
                if(amapIp.Status == "1") {
                    return amapIp.Regeocode.AddressComponent.Adcode;
                }
            }
            return null;
        }
    }


    /// <summary>
    /// 淘宝IP
    /// </summary>
    abstract class TaoBaoIpBase {
        public int Code { get; set; }
    }

    class TaoBaoIpError: TaoBaoIpBase {
        public string Data { get; set; }
    }

    class TaoBaoIpSuccess: TaoBaoIpBase {
        public TaoBaoData Data { get; set; }
    }

    class TaoBaoData {
        public string Ip { get; set; }

        public string Country { get; set; }

        public string Area { get; set; }

        public string Region { get; set; }

        public string City { get; set; }

        public string County { get; set; }

        public string Isp { get; set; }

        public string Country_Id { get; set; }

        public string Area_Id { get; set; }

        public string Region_Id { get; set; }

        public string City_Id { get; set; }

        public string County_Id { get; set; }

        public string Isp_Id { get; set; }
    }


    /// <summary>
    /// 高德IP
    /// </summary>
    class AmapIp {
        public int Status { get; set; }

        public string Info { get; set; }

        public string InfoCode { get; set; }

        public string Province { get; set; }

        public string City { get; set; }

        public string Adcode { get; set; }

        public string Rectangle { get; set; }
    }

    class AmapGeocodeParam {
        public override string ToString() {
            var properties = GetType().GetProperties();
            string result = string.Empty;
            foreach(var propertyInfo in properties) {
                var value = propertyInfo.GetValue(this, null);
                string name = propertyInfo.Name;

                if(value != null) {
                    if(!result.IsNullOrWhiteSpace()) {
                        result += "&";
                    }
                    result += name.ToLower() + "=" + Uri.EscapeDataString(value.ToString()).Replace("%20", "+");
                }
            }
            return result;
        }

        public AmapGeocodeParam(string key, Coordinate coordinate) {
            Key = key;
            Coordinate = coordinate;
        }

        /// <summary>
        /// 请求服务权限标识
        /// </summary>
        public string Key { get; set; }

        /// <summary>
        /// 经纬度坐标
        /// </summary>
        public Coordinate Coordinate { get; set; }

        /// <summary>
        /// 经纬度坐标
        /// </summary>
        public string Location => Coordinate.ToString(CoordinateSystem.GCJ_02);

        /// <summary>
        /// 
        /// </summary>
        public string PoiType { get; set; }

        [Range(0, 3000)]
        public int? Radius { get; set; }

        /// <summary>
        /// 返回结果控制
        /// <list type="string">all</list>
        /// <list type="string">base</list>
        /// </summary>
        public string Extensions { get; set; }

        /// <summary>
        /// 批量查询控制
        /// </summary>
        public bool Batch { get; set; }

        /// <summary>
        /// 道路等级
        /// </summary>
        public int? RoadLevel { get; set; }

        /// <summary>
        /// 数字签名
        /// </summary>
        public string Sig { get; set; }

        /// <summary>
        /// 返回数据格式类型
        /// <remarks>
        /// 可选值：JSON，XML
        /// </remarks>
        /// </summary>
        public string Output
        {
            get => _output;
            set
            {
                if(value.ToLower() != "json" || value.ToLower() != "xml") {
                    throw new AbpValidationException(nameof(AmapGeocodeParam) + "属性" + nameof(Output) + "赋值类型不对!");
                }
                _output = value;
            }
        }

        private string _output = "json";

        /// <summary>
        /// 回调函数
        /// <remarks>
        /// callback值是用户定义的函数名称，此参数只在<seealso cref="Output"/> =JSON时有效
        /// </remarks>
        /// </summary>
        public string Callback { get; set; }

        /// <summary>
        /// 是否优化POI返回顺序
        /// <remarks>
        /// 可选参数:0，1，2
        /// 默认:0
        /// 0：不优化。
        /// 1：综合大数据将居家相关的主POI结果优先返回，即优化pois字段之中的poi顺序。
        /// 2：综合大数据将公司相关的主POI结果优先返回，即优化pois字段之中的poi顺序。
        /// </remarks>
        /// </summary>
        public int? Homeorcorp { get; set; }
    }

    class Rootobject {
        public string Status { get; set; }
        public string Info { get; set; }
        public string Infocode { get; set; }
        public RegeoCode Regeocode { get; set; }
    }

    class RegeoCode {
        public string Formatted_Address { get; set; }
        public Addresscomponent AddressComponent { get; set; }
        public Pois[] Pois { get; set; }
        public Road[] Roads { get; set; }
        public Roadinter[] Roadinters { get; set; }
        public Aois[] Aois { get; set; }
    }

    class Addresscomponent {
        public string Country { get; set; }
        public string Province { get; set; }
        public object[] City { get; set; }
        public string Citycode { get; set; }
        public string District { get; set; }
        public string Adcode { get; set; }
        public string Township { get; set; }
        public string Towncode { get; set; }
        public Neighborhood Neighborhood { get; set; }
        public Building Building { get; set; }
        public Streetnumber StreetNumber { get; set; }
        public Businessarea[] BusinessAreas { get; set; }
    }

    class Neighborhood {
        public object Name { get; set; }
        public object Type { get; set; }
    }

    class Building {
        public object Name { get; set; }
        public object Type { get; set; }
    }

    class Streetnumber {
        public string Street { get; set; }
        public string Number { get; set; }
        public string Location { get; set; }
        public string Direction { get; set; }
        public string Distance { get; set; }
    }

    class Businessarea {
        public string Location { get; set; }
        public string Name { get; set; }
        public string Id { get; set; }
    }

    class Pois {
        public string Id { get; set; }
        public string Name { get; set; }
        public string Type { get; set; }
        public object Tel { get; set; }
        public string Direction { get; set; }
        public string Distance { get; set; }
        public string Location { get; set; }
        public string Address { get; set; }
        public string Poiweight { get; set; }
        public string Businessarea { get; set; }
    }

    class Road {
        public string Id { get; set; }
        public string Name { get; set; }
        public string Direction { get; set; }
        public string Distance { get; set; }
        public string Location { get; set; }
    }

    class Roadinter {
        public string Direction { get; set; }
        public string Distance { get; set; }
        public string Location { get; set; }
        public string First_Id { get; set; }
        public string First_Name { get; set; }
        public string Second_Id { get; set; }
        public string Second_Name { get; set; }
    }

    class Aois {
        public string Id { get; set; }
        public string Name { get; set; }
        public string Adcode { get; set; }
        public string Location { get; set; }
        public string Area { get; set; }
        public string Type { get; set; }
    }
}